gsk: Add GL driver API to create render targets
authorEmmanuele Bassi <ebassi@gnome.org>
Tue, 12 Jul 2016 14:41:31 +0000 (15:41 +0100)
committerEmmanuele Bassi <ebassi@gnome.org>
Tue, 18 Oct 2016 10:49:09 +0000 (11:49 +0100)
It's going to be used by the GL renderer to safely create and bind
FBOs when needed.

gsk/gskgldriver.c
gsk/gskgldriverprivate.h

index 1a2a289320ecf8f1c72267f3d0223fd3a7467b3a..01caa00050d8fa341e96fe3e3d5a395ff8a49145 100644 (file)
@@ -13,6 +13,7 @@ typedef struct {
   int height;
   GLuint min_filter;
   GLuint mag_filter;
+  GArray *fbos;
 } Texture;
 
 typedef struct {
@@ -28,12 +29,15 @@ struct _GskGLDriver
 
   GdkGLContext *gl_context;
 
+  GLuint default_fbo;
+
   GHashTable *textures;
   GArray *vaos;
 
   Texture *bound_source_texture;
   Texture *bound_mask_texture;
   Vao *bound_vao;
+  GLuint bound_fbo;
 
   gboolean in_frame : 1;
 };
@@ -60,10 +64,19 @@ texture_free (gpointer data)
 {
   Texture *t = data;
 
+  g_clear_pointer (&t->fbos, g_array_unref);
   glDeleteTextures (1, &t->texture_id);
   g_slice_free (Texture, t);
 }
 
+static void
+fbo_clear (gpointer data)
+{
+  GLuint fbo_id = GPOINTER_TO_UINT (data);
+
+  glDeleteFramebuffers (1, &fbo_id);
+}
+
 static void
 vao_clear (gpointer data)
 {
@@ -168,6 +181,9 @@ gsk_gl_driver_begin_frame (GskGLDriver *driver)
 
   driver->in_frame = TRUE;
 
+  glGetIntegerv (GL_FRAMEBUFFER_BINDING, (GLint *) &driver->default_fbo);
+  driver->bound_fbo = driver->default_fbo;
+
   glActiveTexture (GL_TEXTURE0);
   glBindTexture (GL_TEXTURE_2D, 0);
 
@@ -193,6 +209,7 @@ gsk_gl_driver_end_frame (GskGLDriver *driver)
   driver->bound_source_texture = NULL;
   driver->bound_mask_texture = NULL;
   driver->bound_vao = NULL;
+  driver->bound_fbo = driver->default_fbo;
 
   g_hash_table_remove_all (driver->textures);
   g_array_set_size (driver->vaos, 0);
@@ -200,6 +217,29 @@ gsk_gl_driver_end_frame (GskGLDriver *driver)
   driver->in_frame = FALSE;
 }
 
+static Texture *
+gsk_gl_driver_get_texture (GskGLDriver *driver,
+                           int          texture_id)
+{
+  return g_hash_table_lookup (driver->textures, GINT_TO_POINTER (texture_id));
+}
+
+static Vao *
+gsk_gl_driver_get_vao (GskGLDriver *driver,
+                       int          vao_id)
+{
+  int i;
+
+  for (i = 0; i < driver->vaos->len; i++)
+    {
+      Vao *v = &g_array_index (driver->vaos, Vao, i);
+      if (v->vao_id == vao_id)
+        return v;
+    }
+
+  return NULL;
+}
+
 int
 gsk_gl_driver_create_texture (GskGLDriver     *driver,
                               int              width,
@@ -273,27 +313,34 @@ gsk_gl_driver_create_vao_for_quad (GskGLDriver   *driver,
   return vao_id;
 }
 
-static Texture *
-gsk_gl_driver_get_texture (GskGLDriver *driver,
-                           int          texture_id)
+int
+gsk_gl_driver_create_render_target (GskGLDriver *driver,
+                                    int          texture_id)
 {
-  return g_hash_table_lookup (driver->textures, GINT_TO_POINTER (texture_id));
-}
+  Texture *t;
+  GLuint fbo_id;
 
-static Vao *
-gsk_gl_driver_get_vao (GskGLDriver *driver,
-                       int          vao_id)
-{
-  int i;
+  g_return_val_if_fail (GSK_IS_GL_DRIVER (driver), -1);
 
-  for (i = 0; i < driver->vaos->len; i++)
+  t = gsk_gl_driver_get_texture (driver, texture_id);
+  if (t == NULL)
+    return -1;
+
+  if (t->fbos == NULL)
     {
-      Vao *v = &g_array_index (driver->vaos, Vao, i);
-      if (v->vao_id == vao_id)
-        return v;
+      t->fbos = g_array_new (FALSE, FALSE, sizeof (GLuint));
+      g_array_set_clear_func (t->fbos, fbo_clear);
     }
 
-  return NULL;
+  glGenFramebuffers (1, &fbo_id);
+  glBindFramebuffer (GL_FRAMEBUFFER, fbo_id);
+  glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, t->texture_id, 0);
+
+  g_array_append_val (t->fbos, fbo_id);
+
+  glBindFramebuffer (GL_FRAMEBUFFER, driver->default_fbo);
+
+  return fbo_id;
 }
 
 void
@@ -366,6 +413,33 @@ gsk_gl_driver_bind_vao (GskGLDriver *driver,
     }
 }
 
+void
+gsk_gl_driver_bind_render_target (GskGLDriver *driver,
+                                  int          texture_id)
+{
+  GLuint fbo_id;
+  Texture *t;
+
+  g_return_if_fail (GSK_IS_GL_DRIVER (driver));
+  g_return_if_fail (driver->in_frame);
+
+  t = gsk_gl_driver_get_texture (driver, texture_id);
+  if (t == NULL)
+    return;
+
+  if (t->fbos == NULL)
+    fbo_id = driver->default_fbo;
+  else
+    fbo_id = g_array_index (t->fbos, GLuint, 0);
+
+  if (fbo_id != driver->bound_fbo)
+    {
+      glBindFramebuffer (GL_FRAMEBUFFER, fbo_id);
+
+      driver->bound_fbo = fbo_id;
+    }
+}
+
 void
 gsk_gl_driver_render_surface_to_texture (GskGLDriver     *driver,
                                          cairo_surface_t *surface,
index 9fc1d8ad3b83ca81687a04ba53d77c6531329247..d5ddf46f206c58d7f78f697923f6662ed1b36e3f 100644 (file)
@@ -31,6 +31,8 @@ int             gsk_gl_driver_create_vao_for_quad       (GskGLDriver     *driver
                                                          int              uv_id,
                                                          int              n_vertices,
                                                          GskQuadVertex   *vertices);
+int             gsk_gl_driver_create_render_target      (GskGLDriver     *driver,
+                                                         int              texture_id);
 
 void            gsk_gl_driver_bind_source_texture       (GskGLDriver     *driver,
                                                          int              texture_id);